package util

import (
	"gitee.com/lstack_light/light-utils/common"
	"net"
	"net/http"
	"strings"
)

var (
	// 常见内网ip
	localIPs = []string{"10.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "172.17.0.0/12", "172.18.0.0/12",
		"172.19.0.0/12", "172.20.0.0/12", "172.21.0.0/12", "172.22.0.0/12", "172.23.0.0/12", "172.24.0.0/12",
		"172.25.0.0/12", "172.26.0.0/12", "172.27.0.0/12", "172.28.0.0/12", "172.29.0.0/12", "172.30.0.0/12",
		"172.31.0.0/12", "192.168.0.0/16"}
)

// HasLocalIPAddr
/**
 * 功能描述：判断是否是内网ip地址
 * @author KangXu
 * @param ip ip地址字符串
 * @return bool
 */
func HasLocalIPAddr(ip string) bool {
	return HasLocalIP(net.ParseIP(ip))
}

// HasLocalIP
/**
 * 功能描述：判断是否是内网ip地址
 * @author KangXu
 * @param ip ip地址
 * @return bool
 */
func HasLocalIP(ip net.IP) bool {
	for _, localIP := range localIPs {
		if strings.Contains(localIP, ip.String()) {
			return true
		}
	}
	return ip.IsLoopback()
}

// GetClientLocalIP
/**
 * 功能描述：获取真实的客户端内网ip
 * @author KangXu
 * @param r http请求
 * @return string
 */
func GetClientLocalIP(r *http.Request) string {
	proxy := r.Header.Get(common.XForwardedFor)
	ip := strings.TrimSpace(strings.Split(proxy, ",")[0])
	if "" != ip {
		return ip
	}
	ip = strings.TrimSpace(r.Header.Get(common.XRealIp))
	if "" != ip {
		return ip
	}
	if realIp, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); nil == err {
		if "::1" == realIp {
			ip = "127.0.0.1"
		} else {
			ip = realIp
		}
	}
	return ip
}

// GetClientPublicIP
/**
 * 功能描述：获取真实的客户端公网ip
 * @author KangXu
 * @param r http请求
 * @return string
 */
func GetClientPublicIP(r *http.Request) string {
	ip := ""
	for _, ip = range strings.Split(r.Header.Get(common.XForwardedFor), ",") {
		ip = strings.TrimSpace(ip)
		if "" != ip && !HasLocalIPAddr(ip) {
			return ip
		}
	}

	ip = strings.TrimSpace(r.Header.Get(common.XRealIp))
	if "" != ip && !HasLocalIPAddr(ip) {
		return ip
	}
	if realIp, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); nil == err {
		if !HasLocalIPAddr(realIp) {
			ip = realIp
		}
	}
	return ip
}

// GetClientIP
/**
 * 功能描述：获取真实的客户端ip
 * @author KangXu
 * @param r http请求
 * @return string
 */
func GetClientIP(r *http.Request) string {
	ip := GetClientPublicIP(r)
	if "" == ip {
		ip = GetClientLocalIP(r)
	}
	return ip
}
